#include "win32_thread_pool.h"

#include "debug/logger.h"

namespace renderit
{
	namespace thread
	{
		static void thread_proc(void * p)
		{
			win32_thread_pool * pool = reinterpret_cast<win32_thread_pool*>(p);
			while (true)
			{
				auto f = pool->fetch_work();
				if (f)
				{
					f();
				}
				else
				{
					logger::warn("Thread Pool(%s) Failed To Fetch Work!!!", pool->name().c_str());
				}
			}			
		}

		win32_thread_pool::win32_thread_pool(const std::string& name, uint32 count)
		{
			name_ = name;
			for (uint32 i = 0; i < count; ++i)
			{
				threads_.push_back(create_thread(thread_proc, this));
			}
		}

		void win32_thread_pool::dispatch(std::function<void()>&& func)
		{
			work_queue_lock_.lock();
			work_queue_.push(std::move(func));
			work_queue_lock_.release();
			work_sem_.V();
		}

		std::function<void()> win32_thread_pool::fetch_work()
		{
			work_sem_.P();
			work_queue_lock_.lock();
			auto w = work_queue_.front();
			work_queue_.pop();
			work_queue_lock_.release();
			return w;
		}

		// ----------------------- Main Thread --------------------
		win32_main_thread::win32_main_thread()
		{

		}

		void win32_main_thread::dispatch(std::function<void()>&& func)
		{
			work_queue_lock_.lock();
			work_queue_.push(std::move(func));
			work_queue_lock_.release();
		}

		void win32_main_thread::do_work()
		{
			work_queue_lock_.lock();
			std::queue<std::function<void()>> tmp;
			std::swap(tmp, work_queue_);
			work_queue_lock_.release();
			while (tmp.size())
			{
				auto w = tmp.front();
				if (w)
				{
					w();
				}
				tmp.pop();
			}
		}
	}
}